import torch
import numpy as np

def unit_vector(vector):
    return vector / np.linalg.norm(vector)


def degree_distance(v1, v2):
    v1_u = unit_vector(v1)
    v2_u = unit_vector(v2)
    return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0))/np.pi * 180

def vector_to_ang(vector):
    """compute angle according to direction vector

    :param vector: direction vector
    :return: theta and phi in spherical coordinate
    """
    vector = np.array(vector)
    # degree between v and [0, 1, 0]
    alpha = degree_distance(vector, [0, 1, 0])
    phi = 90.0 - alpha
    # proj1 is the projection of v onto [0, 1, 0] axis
    proj1 = [0, np.cos(alpha/180.0 * np.pi), 0]
    # proj2 is the projection of v onto the plane([1, 0, 0], [0, 0, 1])
    proj2 = vector - proj1
    # theta = degree between project vector to plane and [1, 0, 0]
    theta = degree_distance(proj2, [1, 0, 0])
    sign = -1.0 if degree_distance(vector, [0, 0, -1]) > 90 else 1.0
    theta = sign * theta
    return theta, phi


def ang_to_geoxy(theta, phi, h, w):
    """compute point coordinate in ERP according to theta and phi

    :param theta: theta in sphere
    :param phi: phi in sphere
    :param h: frame height
    :param w: frame width
    :return: (x, y) in ERP
    """
    x = h/2.0 - (h/2.0) * np.sin(phi/180.0 * np.pi)
    temp = theta
    if temp < 0:
        temp = 180 + temp + 180
    temp = 360 - temp
    y = (temp * 1.0/360 * w)
    return int(x), int(y)


def de_interpolate(raw_tensor, N):
    out = np.zeros((N, 9, 16))
    for idx in range(10):
        out = out + raw_tensor[:, idx::10, idx::10]
    return out / 10


def de_interpolate_frame(raw_tensor):
    out = np.zeros((9, 16, 3))
    for idx in range(10):
        out = out + raw_tensor[idx::10, idx::10, :]
    return out / 10
